package com.boesch.electroOffice.business.businessObjectImpl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.boesch.electroOffice.business.businessObject.StaffBusinessObject;
import com.boesch.electroOffice.business.common.BusinessException;
import com.boesch.electroOffice.business.common.BusinessExceptionMessages;
import com.boesch.electroOffice.dataaccess.common.IllegalDataAccessException;
import com.boesch.electroOffice.dataaccess.dao.AppointmentDao;
import com.boesch.electroOffice.dataaccess.dao.IdentifierDao;
import com.boesch.electroOffice.dataaccess.dao.WorkingHourDao;
import com.boesch.electroOffice.model.electroOffice.Appointment;
import com.boesch.electroOffice.model.electroOffice.Identifier;
import com.boesch.electroOffice.model.electroOffice.WorkingHour;
import com.boesch.electroOffice.model.wrapper.WeekReportEntry;
import com.boesch.electroOffice.utils.DateUtils;
import com.boesch.electroOffice.utils.UserUtils;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;

@Service
public class StaffBusinessObjectImpl implements StaffBusinessObject {

	@Autowired
	private WorkingHourDao workingHourDao;
	@Autowired
	private AppointmentDao appointmentDao;
	@Autowired
	private IdentifierDao identifierDao;

	public List<WeekReportEntry> getWeekReportEntriesByUserIdCalendarWeekAndIdentifier(long userId, int year, int week, Identifier identifier)
			throws IllegalDataAccessException, BusinessException {
		Timestamp startDate = DateUtils.getDateOfMondayByYearAndWeek(year, week);
		Timestamp endDate = DateUtils.getDatePlusDays(startDate, 6);
		List<WorkingHour> workingHours = workingHourDao.readWorkingHoursByUserIdStartDateEndDateAndIdentifier(userId, startDate, endDate, identifier);
		List<WeekReportEntry> reportEntries = mapWorkingHoursToWeekReportEntries(workingHours, identifier, userId, DateUtils.convertTimestampToLocalDate(startDate), true);
		return reportEntries;
	}

	public WeekReportEntry getWeekReportEntryByCalendarWeekAndIdentifier(long userId, int year, int week, Identifier identifier)
			throws IllegalDataAccessException, BusinessException {
		Timestamp startDate = DateUtils.getDateOfMondayByYearAndWeek(year, week);
		Timestamp endDate = DateUtils.getDatePlusDays(startDate, 6);
		List<WorkingHour> workingHours = workingHourDao.readWorkingHoursByUserIdStartDateEndDateAndIdentifier(userId, startDate, endDate, identifier);
		List<WeekReportEntry> reportEntries = mapWorkingHoursToWeekReportEntries(workingHours, identifier, userId, DateUtils.convertTimestampToLocalDate(startDate),
				false);
		if (reportEntries.size() > 0) {
			return reportEntries.get(0);
		}
		return new WeekReportEntry();
	}

	public String saveWeekReportEntry(WeekReportEntry entry, User currentUser) throws IllegalDataAccessException, BusinessException {
		return workingHourDao.saveWeekReportEntry(entry, currentUser);
	}

	private List<WeekReportEntry> mapWorkingHoursToWeekReportEntries(List<WorkingHour> workingHours, Identifier identifier, long userId, LocalDate startDate,
			boolean needSizeTen) throws IllegalDataAccessException, BusinessException {
		Map<String, WeekReportEntry> reportEntries = new HashMap<String, WeekReportEntry>();
		List<WeekReportEntry> entries = new ArrayList<WeekReportEntry>();
		try {
			Appointment appointment = null;
			User user = null;
			for (WorkingHour workingHour : workingHours) {
				Integer appointmentId = workingHour.getAppointmentId();
				if (null != appointmentId && appointmentId > 0) {
					appointment = appointmentDao.readAppointmentById(appointmentId);
				}

				if (null == user) {
					user = UserLocalServiceUtil.getUserById(userId);
				}

				String key = identifier.getName() + appointmentId;
				WeekReportEntry reportEntry = reportEntries.get(key);

				if (null == reportEntry) {
					reportEntry = new WeekReportEntry();
				}

				reportEntry.setAppointment(appointment);
				reportEntry.setWorkingIdentifier(identifier);
				reportEntry.setUser(user);

				setWorkingHour(workingHour, reportEntry);

				reportEntries.put(key, reportEntry);
			}
			entries = new ArrayList<WeekReportEntry>(reportEntries.values());

			addDefaultWeekReportEntry(entries, identifier, startDate);

			if (needSizeTen) {
				for (int i = entries.size(); i < 10; i++) {
					addDefaultWeekReportEntry(entries, identifier, startDate);
				}
			}
		} catch (PortalException e) {
			throw new BusinessException(BusinessExceptionMessages.USER_NOT_FOUND.getValue(), e);
		} catch (SystemException e) {
			throw new BusinessException(BusinessExceptionMessages.USER_NOT_FOUND.getValue(), e);
		}
		return entries;
	}

	private void addDefaultWeekReportEntry(List<WeekReportEntry> entries, Identifier workingIdentifier, LocalDate startDate) {
		User currentUser = UserUtils.getCurrentUser();
		WeekReportEntry entry = new WeekReportEntry();
		entry.setWorkingIdentifier(workingIdentifier);

		entry.setMonday(createWorkingHour(workingIdentifier, startDate, 0, currentUser));
		entry.setTuesday(createWorkingHour(workingIdentifier, startDate, 1, currentUser));
		entry.setWednesday(createWorkingHour(workingIdentifier, startDate, 2, currentUser));
		entry.setThursday(createWorkingHour(workingIdentifier, startDate, 3, currentUser));
		entry.setFriday(createWorkingHour(workingIdentifier, startDate, 4, currentUser));
		entry.setSaturday(createWorkingHour(workingIdentifier, startDate, 5, currentUser));
		entry.setSunday(createWorkingHour(workingIdentifier, startDate, 6, currentUser));
		entry.setIsDefault(true);
		entries.add(entry);
	}

	private WorkingHour createWorkingHour(Identifier workingIdentifier, LocalDate startDate, int plusDays, User currentUser) {
		WorkingHour workingHour = new WorkingHour();
		workingHour.setWorkingIdentifier(workingIdentifier);
		workingHour.setLrUserId(currentUser.getUserId());
		workingHour.setWorkdate(DateUtils.getDatePlusDays(startDate, plusDays));
		workingHour.setHours(0.0);
		return workingHour;
	}

	private void setWorkingHour(WorkingHour workingHour, WeekReportEntry reportEntry) {
		Integer dayOfWeek = workingHour.getWorkdate().getDayOfWeek();
		switch (dayOfWeek) {
		case 1:
			reportEntry.setMonday(workingHour);
			break;
		case 2:
			reportEntry.setTuesday(workingHour);
			break;
		case 3:
			reportEntry.setWednesday(workingHour);
			break;
		case 4:
			reportEntry.setThursday(workingHour);
			break;
		case 5:
			reportEntry.setFriday(workingHour);
			break;
		case 6:
			reportEntry.setSaturday(workingHour);
			break;
		case 7:
			reportEntry.setSunday(workingHour);
			break;
		}
	}
}
